/* Copyright 2012 Dustin Mitchell <dmmitche [at] gmail [dot] com>
 *
 * Licensed under the GPLv3.  See included LICENSE.txt for full details.
 */

#include <string.h>

#include "message_handler.h"
#include "log.h"

int message_handler_create (struct message_handler *handler)
{
  if (!handler)
    return -1;

  return sync_queue_create (&handler->msg_queue);
}

void message_handler_destroy (struct message_handler *handler)
{
  if (!handler)
    return;

  sync_queue_destroy (&handler->msg_queue);
}

int message_handler_post (struct message_handler *handler,
                          struct ref_cnt *msg)
{
  if (!handler || !msg)
    return -1;

  if (ref_cnt_ref (msg) == -1) {
    log (LOG_ERR, "unable to grab ref_cnt");
    return -1;
  }

  if (sync_queue_insert (&handler->msg_queue, msg) == -1) {
    log (LOG_ERR, "unable to insert message into queue");
    ref_cnt_deref (msg);
    return -1;
  }

  return 0;
}

int message_handler_wait (struct message_handler *handler,
                          union message *msg)
{
  struct ref_cnt *msg_ref;

  if (!handler || !msg)
    return -1;

  msg_ref = (struct ref_cnt *)sync_queue_remove (&handler->msg_queue);
  if (!msg_ref) {
    log (LOG_ERR, "unable to remove message from queue");
    return -1;
  }

  memcpy (msg, ref_cnt_get_obj (msg_ref), sizeof (union message));

  ref_cnt_deref (msg_ref);

  return 0;
}

int message_handler_peek (struct message_handler *handler,
                          union message *msg)
{
  struct ref_cnt *msg_ref;
  int status;

  if (!handler || !msg)
    return -1;

  msg_ref = (struct ref_cnt *)sync_queue_tryremove (&handler->msg_queue,
                                                    &status);
  if (!msg_ref && status) {
    log (LOG_ERR, "unable to remove message from queue");
    return -1;
  }

  if (!status)
    return 0;

  memcpy (msg, ref_cnt_get_obj (msg_ref), sizeof (union message));

  ref_cnt_deref (msg_ref);

  return 1;
}
